"use strict";

import { chunk } from "./array";
/**
 * 按照给定的格式，对日期进行格式化
 * @param {Date|Number|String} date 日期
 * @param {String} format 格式
 * @returns {String} 格式化之后的日期
 */
export var format = (function () {
    var rword = /[^, ]+/g; //切割字符串为一个个小块，以空格或豆号分开它们，结合replace实现字符串的forEach
    var oproto = Object.prototype;
    var serialize = oproto.toString;
    var class2type = {};
    "Boolean Number String Function Array Date RegExp Object Error".replace(rword, function (name) {
        class2type["[object " + name + "]"] = name.toLowerCase()
    });

    /**
     * 转出数字
     * @param {String} str 字符串
     */
    function toInt(str) {
        return parseInt(str, 10)
    }

    function padNumber(num, digits, trim) {
        var neg = ""
        if (num < 0) {
            neg = '-';
            num = -num;
        }

        num = "" + num;
        while (num.length < digits)
            num = "0" + num;
        if (trim)
            num = num.substr(num.length - digits)
        return neg + num;
    }

    function dateGetter(name, size, offset, trim) {
        return function (date) {
            var value = date["get" + name]()
            if (offset > 0 || value > -offset)
                value += offset;
            if (value === 0 && offset === -12) {
                value = 12;
            }
            return padNumber(value, size, trim)
        }
    }

    function dateStrGetter(name, shortForm) {
        return function (date, formats) {
            var value = date["get" + name]()
            var get = (shortForm ? ("SHORT" + name) : name).toUpperCase()
            return formats[get][value]
        }
    }

    function timeZoneGetter(date) {
        var zone = -1 * date.getTimezoneOffset()
        var paddedZone = (zone >= 0) ? "+" : ""
        paddedZone += padNumber(Math[zone > 0 ? "floor" : "ceil"](zone / 60), 2) + padNumber(Math.abs(zone % 60), 2)
        return paddedZone
    }

    function ampmGetter(date, formats) {
        return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1]
    }
    var rfixYMD = /^(\d+)\D(\d+)\D(\d+)/
    var DATE_FORMATS = {
        yyyy: dateGetter("FullYear", 4),
        yy: dateGetter("FullYear", 2, 0, true),
        y: dateGetter("FullYear", 1),
        MMMM: dateStrGetter("Month"),
        MMM: dateStrGetter("Month", true),
        MM: dateGetter("Month", 2, 1),
        M: dateGetter("Month", 1, 1),
        dd: dateGetter("Date", 2),
        d: dateGetter("Date", 1),
        HH: dateGetter("Hours", 2),
        H: dateGetter("Hours", 1),
        hh: dateGetter("Hours", 2, -12),
        h: dateGetter("Hours", 1, -12),
        mm: dateGetter("Minutes", 2),
        m: dateGetter("Minutes", 1),
        ss: dateGetter("Seconds", 2),
        s: dateGetter("Seconds", 1),
        sss: dateGetter("Milliseconds", 3),
        EEEE: dateStrGetter("Day"),
        EEE: dateStrGetter("Day", true),
        a: ampmGetter,
        Z: timeZoneGetter
    }

    var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,

        NUMBER_STRING = /^\d+$/;

    var riso8601 = /^(\d{4})-?(\d+)-?(\d+)(?:T(\d+)(?::?(\d+)(?::?(\d+)(?:\.(\d+))?)?)?(Z|([+-])(\d+):?(\d+))?)?$/;

    var locate = {
        AMPMS: {
            0: "上午",
            1: "下午"
        },

        DAY: {
            0: "星期日",
            1: "星期一",
            2: "星期二",
            3: "星期三",
            4: "星期四",
            5: "星期五",
            6: "星期六"
        },

        MONTH: {
            0: "1月",
            1: "2月",
            2: "3月",
            3: "4月",
            4: "5月",
            5: "6月",
            6: "7月",
            7: "8月",
            8: "9月",
            9: "10月",
            10: "11月",
            11: "12月"
        },

        SHORTDAY: {
            "0": "周日",
            "1": "周一",
            "2": "周二",
            "3": "周三",
            "4": "周四",
            "5": "周五",
            "6": "周六"
        },

        fullDate: "y年M月d日EEEE",
        longDate: "y年M月d日",
        medium: "yyyy-M-d H:mm:ss",
        mediumDate: "yyyy-M-d",
        mediumTime: "H:mm:ss",
        "short": "yy-M-d ah:mm",
        shortDate: "yy-M-d",
        shortTime: "ah:mm"
    }

    locate.SHORTMONTH = locate.MONTH

    function checkType(obj) { //取得目标的类型

        if (obj == null) {
            return String(obj)
        }

        // 早期的webkit内核浏览器实现了已废弃的ecma262v4标准，可以将正则字面量当作函数使用，因此typeof在判定正则时会返回function

        return typeof obj === "object" || typeof obj === "function" ?
            class2type[serialize.call(obj)] || "object" :
            typeof obj

    }

    function jsonStringToDate(string) {
        string = string.replace(/\s/g, "T")
        var match
        if (match = string.match(riso8601)) {
            var date = new Date(0),
                tzHour = 0,
                tzMin = 0,
                dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
                timeSetter = match[8] ? date.setUTCHours : date.setHours

            if (match[9]) {
                tzHour = toInt(match[9] + match[10])
                tzMin = toInt(match[9] + match[11])
            }

            dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]))
            var h = toInt(match[4] || 0) - tzHour
            var m = toInt(match[5] || 0) - tzMin
            var s = toInt(match[6] || 0)
            var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000)
            timeSetter.call(date, h, m, s, ms)
            return date
        }

        return string
    }

    return function (date, format) {
        if (date === '') { //为空字符串的处理
            return '';
        }

        var text = "",
            parts = [],
            fn, match;

        format = format || "mediumDate"
        format = locate[format] || format
        if (typeof date === "string") {
            if (NUMBER_STRING.test(date)) {
                date = toInt(date)
            } else {
                var trimDate = date.trim()
                date = trimDate.replace(rfixYMD, function (a, b, c, d) {
                    var array = d.length === 4 ? [d, b, c] : [b, c, d]
                    return array.join("-")
                })

                date = jsonStringToDate(date)
            }

            date = new Date(date)
        }

        if (typeof date === "number") {
            date = new Date(date)
        }

        if (checkType(date) !== "date") {
            return
        }

        while (format) {
            match = DATE_FORMATS_SPLIT.exec(format)
            if (match) {
                parts = parts.concat(match.slice(1))
                format = parts.pop()
            } else {
                parts.push(format)
                format = null
            }

        }

        parts.forEach(function (value) {
            fn = DATE_FORMATS[value]
            text += fn ? fn(date, locate) : value.replace(/(^'|'$)/g, "").replace(/''/g, "'")
        });
        return text == "undefined" ? "" : text;

    }
}());

/**
 * 获取42天，用于日历
 * @param {Number} year 年
 * @param {Number} month  月
 * @param {Object} options  - 是否获取其他月份anotherVisible
 * @returns {Array}
 */
export var getDays = function (year, month, opt) {
    var {
        anotherVisible = true,
        beginAtSunday = false
    }=opt||{};
    var firstDay = new Date(year, month, 1);
    var week = firstDay.getDay();
    //星期天
    if (week == 0) week = 7;

    //补的天数
    var prefill = week - 1;
    if (prefill == 0) prefill = 7;
    //前一天，和最后一天的日期
    var beforeOfFirstDay = new Date(year, month, 0).getDate(),
        lastDay = new Date(year, month + 1, 0).getDate();
    var ret = [];
    for (let i = 1; i <= 42; i++) {
        var day = i - prefill;
        if (day <= 0) {
            //上个月
            if(!anotherVisible){
                ret.push({})
                continue;
            }
            day += beforeOfFirstDay;
        } else if (day > lastDay) {
            //下个月
            if(!anotherVisible){
                ret.push({})
                continue;
            }
            day -= lastDay;
        }
        var rday =i - prefill;
        ret.push({
            name: day,
            month: month,
            year: year,
            day:rday,
            another:rday <= 0||rday > lastDay,
            time:new Date(year, month, rday).getTime()
        });
    }
    return chunk(ret,7)
}
